package com.syg.jvm;

import java.util.concurrent.TimeUnit;

/**
 * 导致 JVM 的退出只有下面这 2 种情况：
 *      1,所有的非 daemon 进程退出
 *      2,某个线程调用了 System.exit( ) 或 Runtime.exit() 显式退出进程
 *
 *
 *
 * @author syg
 *
 */
public class Daemon {

    /**
     * 主线程是main线程,非守护线程可以理解为业务线程,守护线程可以是垃圾回收之类的线程
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        // test1();
        test2();
    }

    /**
     * 非守护线程不退出,jvm不会退出
     * @throws InterruptedException
     */
    public static void test1() throws InterruptedException {
        // 在主线程中,new一个非守护线程
        Thread thread = new Thread(() -> {
            // 模拟非守护线程不退出的情况
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("I am running ...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });

        // 启动线程
        thread.start();

        TimeUnit.SECONDS.sleep(2);

        // 主线程即将退出
        System.out.println("The main thread ready to exit ...");
    }

    /**
     * 通过test1() 与test2()得出的结论：
     *      非守护线程没有结束,jvm不会退出
     *      守护线程有木有结束,不影响jvm的退出
     *      换句话说，守护线程拥有自动结束自己生命周期的特性，而非守护线程不具备这个特点。
     *
     * 为什么守护线程不影响jvm的退出？
     *      当JVM 中没有一个正在运行的非守护线程，这个时候，JVM 会退出。换句话说，守护线程拥有自动结束自己生命周期的特性，而非守护线程不具备这个特点。
     *      JVM 中的垃圾回收线程就是典型的守护线程，如果说不具备该特性，会发生什么呢？
     *          当 JVM 要退出时，由于垃圾回收线程还在运行着，导致程序无法退出，这就很尴尬了！！！由此可见，守护线程的重要性了。
     * 通常来说，守护线程经常被用来执行一些后台任务，但是呢，你又希望在程序退出时，或者说 JVM 退出时，线程能够自动关闭，此时，守护线程是你的首选。
     * @throws InterruptedException
     */
    public static void test2() throws InterruptedException {
        // 设置一个钩子线程,在jvm退出时输出日志
        Runtime.getRuntime().addShutdownHook(new Thread(()->System.out.println(" The jvm exit success !!!")));

        // 在主线程中new一个线程
        Thread thread = new Thread(() -> {
            // 模拟守护线程不退出的情况
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("I am running ...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 将该线程设置为守护线程
        thread.setDaemon(true);

        // 启动线程
        thread.start();

        TimeUnit.SECONDS.sleep(2);

        // 主线程即将退出
        System.out.println("The main thread ready to exit ...");
    }
}
